package com.se.service;

import cn.hutool.core.lang.Pair;
import com.se.dao.mysql.ActDao;
import com.se.dao.mysql.ApplyDao;
import com.se.dao.mysql.QuestionDao;
import com.se.dao.mysql.UserDao;
import com.se.domain.dto.QStaDTO;
import com.se.domain.mysql.*;
import com.se.domain.request.param.ListApplyUserParam;
import com.se.domain.vo.*;
import com.se.enums.ResultCode;
import com.se.exception.ResultException;
import com.se.util.MyDateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class ActStaService {

    @Autowired
    ActService actService;
    @Autowired
    ApplyDao applyDao;
    @Autowired
    UserDao userDao;
    @Autowired
    ActDao actDao;
    @Autowired
    QuestionDao questionDao;

    public List<ApplyVO> listApplyUser(ListApplyUserParam param, Long userId) throws ResultException {

        ActivityDO activityDO = actService.checkModifyAct(param.getActId(), userId);
        if(!actService.checkPublish(activityDO)){
            throw new ResultException(ResultCode.STA_NO_PUBLISH);
        }
        List<ApplyDO> applyDOList = applyDao.listUserApplyByQnId(activityDO.getQnId(), param.getPage());

        if(applyDOList.isEmpty()){
            return Collections.emptyList();
        }

        List<Long> userIds = new ArrayList<>();
        for (ApplyDO applyDO : applyDOList) {
            userIds.add(applyDO.getUserId());
        }

        Map<Long, UserVO> userVOMap = userDao.mapVOByUserIds(userIds);

        List<ApplyVO> res = new ArrayList<>();

        for (ApplyDO applyDO : applyDOList) {
            UserVO userVO = userVOMap.get(applyDO.getUserId());
            ApplyVO applyVO = new ApplyVO(applyDO);
            applyVO.setUser(userVO);

            res.add(applyVO);
        }

        return res;
    }

    public ApplyVO getApplyInfo(Long actId, Long applyId, Long userId) throws ResultException {
        ApplyDO applyDO = applyDao.getByApplyId(applyId);
        if(applyDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }
        ActivityDO activityDO = actDao.getByQnId(applyDO.getQnId());
        if(activityDO == null || !Objects.equals(actId, activityDO.getActId())){
            throw new ResultException(ResultCode.NO_OBJECT);
        }
        if(!Objects.equals(activityDO.getUserId(), userId)){
            throw new ResultException(ResultCode.NO_PERM);
        }
        UserVO userVO = userDao.getVOByUserId(applyDO.getUserId());
        List<QVO> qvoList = questionDao.listQVOByQnId(activityDO.getQnId());
        //装填报名人答案
        Map<Long, String> ansMap = applyDao.mapQRecordAnsByApplyId(applyId);
        for (QVO qvo : qvoList) {
            String ans = ansMap.get(qvo.getQId());
            qvo.setAns(ans);
        }


        ApplyVO applyVO = new ApplyVO(applyDO);
        applyVO.setUser(userVO);
        applyVO.setQn(qvoList);


        return applyVO;
    }

    public ApplyQRecordVO listApplyQRecord(Long actId, Long qId, Long userId) throws ResultException {
        //检查
        QuestionDO questionDO = questionDao.getByQId(qId);
        if(questionDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }

        ActivityDO activityDO = actDao.getByQnId(questionDO.getQnId());
        if(activityDO == null || !Objects.equals(actId, activityDO.getActId())){
            throw new ResultException(ResultCode.NO_OBJECT);
        }
        if(!Objects.equals(activityDO.getUserId(), userId)){
            throw new ResultException(ResultCode.NO_PERM);
        }

        ApplyQRecordVO res = new ApplyQRecordVO();


        //查询Question
        QVO qvo = new QVO(questionDO);
        List<OptionVO> optionVOList = questionDao.listOVOByQId(qId);
        qvo.setOptions(optionVOList);
        res.setQ(qvo);

        //查询Records
        List<RecordDO> recordDOList = applyDao.listRecordsByQId(qId);
        if(recordDOList.isEmpty()){
            return res;
        }
        List<Long> userIds = new ArrayList<>();
        for (RecordDO recordDO : recordDOList) {
            userIds.add(recordDO.getUserId());
        }

        Map<Long, UserVO> userVOMap = userDao.mapVOByUserIds(userIds);

        List<RecordVO> recordVOList = new ArrayList<>();
        for (RecordDO recordDO : recordDOList) {
            RecordVO recordVO = new RecordVO(recordDO);
            recordVO.setUser(userVOMap.get(recordDO.getUserId()));

            recordVOList.add(recordVO);
        }

        res.setRecords(recordVOList);

        return res;
    }

    public Pair<ActivityDO, Workbook> generateApplyExcel(Long actId, Long userId) throws ResultException {
        ActivityDO activityDO = actService.checkModifyAct(actId, userId);
        if(!actService.checkPublish(activityDO)){
            throw new ResultException(ResultCode.STA_NO_PUBLISH);
        }

        Workbook workbook = new SXSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet 1");
        int rowIndex = 0;
        rowIndex = this.putActInfoInSheet(activityDO, sheet, rowIndex);

        List<QVO> qvoList = questionDao.listQVOByQnId(activityDO.getQnId());
        List<QStaDTO> qStaDTOList = qvoList.stream().map(QStaDTO::new).toList();
        rowIndex = this.putHeadAndQuestion(qStaDTOList, sheet, rowIndex);

        List<ApplyDO> applyDOList = applyDao.listUserApplyByQnId(activityDO.getQnId());
        for (ApplyDO applyDO : applyDOList) {
            Map<Long, String> ansMap = applyDao.mapQRecordAnsByApplyId(applyDO.getApplyId());
            UserVO userVO = userDao.getVOByUserId(applyDO.getUserId());
            rowIndex = this.putUserRecord(applyDO, userVO, ansMap, qStaDTOList, sheet, rowIndex);
        }

        return Pair.of(activityDO, workbook);
    }

    private int putUserRecord(ApplyDO applyDO, UserVO userVO, Map<Long, String> ansMap, List<QStaDTO> qStaDTOList, Sheet sheet, int rowIndex) {

        Row row = sheet.createRow(rowIndex++);
        //用户名
        row.createCell(0).setCellValue(userVO.getUname());

        //报名时间
        row.createCell(1).setCellValue(MyDateUtil.sdf.format(applyDO.getCtime()));

        //是否签到
        String sign = "";
        if(applyDO.getSign() != null){
            sign = applyDO.getSign()?"已签到":"未签到";
        }
        row.createCell(2).setCellValue(sign);


        //装填问卷答案
        for (QStaDTO qStaDTO : qStaDTOList) {
            switch (qStaDTO.getType()){

                case QuestionDO.Type.FILL -> {
                    int cellIndex = qStaDTO.getLeft();
                    row.createCell(cellIndex).setCellValue(ansMap.get(qStaDTO.getQId()));

                }
                case QuestionDO.Type.SINGLE -> {
                    Long oId = Long.parseLong(ansMap.get(qStaDTO.getQId()));
                    Pair<OptionVO, Integer> pair = qStaDTO.getOptionCellMap().get(oId);
                    row.createCell(pair.getValue()).setCellValue(pair.getKey().getInfo());
                }
                case QuestionDO.Type.MULTI -> {
                    String ans = ansMap.get(qStaDTO.getQId());
                    Arrays.stream(ans.split(",")).map(Long::parseLong).forEach(oId -> {
                        Pair<OptionVO, Integer> pair = qStaDTO.getOptionCellMap().get(oId);
                        row.createCell(pair.getValue()).setCellValue(pair.getKey().getInfo());
                    });
                }
            }
        }

        return rowIndex;
    }

    private int putHeadAndQuestion(List<QStaDTO> qStaDTOList, Sheet sheet, int rowIndex) {

        int firstRow = rowIndex;

        Row row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("用户名");
        row.createCell(1).setCellValue("报名时间");
        row.createCell(2).setCellValue("是否签到");

        if(qStaDTOList.isEmpty()){
            return rowIndex;
        }
        //活动问卷不为空
        int firstCell = 3;  //活动问卷的单元格合并左列
        row.createCell(3).setCellValue("活动问卷");

        //题目的行
        int qRowIndex = rowIndex;
        row = sheet.createRow(rowIndex++);
        int lastRow = rowIndex; //用户表头合并的单元格下行,即题目选项的行
        //选项的行
        Row optionRow = sheet.createRow(rowIndex++);
        //列索引
        int cellIndex = firstCell;
        //题目计数
        int qNum = 1;
        for (QStaDTO qStaDTO : qStaDTOList) {
            switch (qStaDTO.getType()){
                case QuestionDO.Type.FILL -> {
                    row.createCell(cellIndex).setCellValue(qNum + ". "+qStaDTO.getTitle());

                    qStaDTO.setLeft(cellIndex);
                    cellIndex++;
                }
                case QuestionDO.Type.SINGLE,QuestionDO.Type.MULTI -> {
                    row.createCell(cellIndex).setCellValue(qNum + ". "+qStaDTO.getTitle());

                    qStaDTO.setLeft(cellIndex);

                    if(qStaDTO.getOptions().isEmpty()){
                        cellIndex++;
                        continue;
                    }

                    qStaDTO.setRight(cellIndex);

                    //选项计数
                    int oNum = 1;
                    for (OptionVO option : qStaDTO.getOptions()) {
                        optionRow.createCell(cellIndex).setCellValue(oNum + ". "+option.getInfo());

                        qStaDTO.setRight(cellIndex);
                        qStaDTO.getOptionCellMap().put(option.getOId(), Pair.of(option, cellIndex));
                        cellIndex++;oNum++;
                    }
                    //合并题目title
                    sheet.addMergedRegion(new CellRangeAddress(qRowIndex, qRowIndex, qStaDTO.getLeft(), qStaDTO.getRight()));
                }
            }

            qNum++;
        }

        //合并用户表头
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, 0, 0));
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, 1, 1));
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, 2, 2));

        //合并活动问卷表头
        sheet.addMergedRegion(new CellRangeAddress(firstRow, firstRow, firstCell, cellIndex-1));

        return rowIndex;
    }

    private int putActInfoInSheet(ActivityDO activityDO, Sheet sheet, int rowIndex) {
        Row row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("活动名称");
        row.createCell(1).setCellValue(activityDO.getTitle());

        row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("活动详情");
        row.createCell(1).setCellValue(activityDO.getInfo());

        row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("开始时间");
        row.createCell(1).setCellValue(activityDO.getStartTime());

        row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("结束时间");
        row.createCell(1).setCellValue(activityDO.getEndTime());

        row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("地点");
        row.createCell(1).setCellValue(activityDO.getPlace());

        row = sheet.createRow(rowIndex++);
        row.createCell(0).setCellValue("人数");
        row.createCell(1).setCellValue(activityDO.sizeNumStr());


        return rowIndex;
    }
}
